// ============ global var ============ // //<>//
int stateMachine = -10;  // splash screen entry
PFont mainFont;

// ============ local var ============ //
int pos = 0;
float zoom;

final color bgColor = #66A57C;
final color fntColor = #CBC577;

final int maxW = 1530;
final int maxH = 630;

String type, file, word = null;
PImage wordImg, logoImg, sealImg, splashImg;

// ============ setup ============ //
void setup() {
  // === basic config === //
  size(1620, 900);
  smooth();
  fill(fntColor);
  frameRate(50);
  mainFont = loadFont("ArialMT-120.vlw");
  textFont(mainFont);

  // === animation pen & cursor === //
  animatePen = new canimatePen("ink bottle.png", "ink bottle & pen.png", "pen.png", "parchment.png", "cursor.png", 840, 745);

  // === image of logo, author seal, cursor === //
  logoImg = loadImage("maths_chem_phy_logo.png");
  sealImg = loadImage("freda_seal.png");

  // === tmo (exit) time based on the len of words array === //
  int tmo;
  if (totalWords <= 10) {
    tmo = 5;
  } else if (totalWords <= 15) {
    tmo = 10;
  } else if (totalWords <= 20) {
    tmo = 15;
  } else {
    tmo = 25;
  }

  // === stopwatch === //
  stopWatch = new cstopWatch(680, 853, #BFB76C, tmo, "thread1sec");

  // === mouse move paging on/off msg === //
  mouseMovePaging = new cmouseMovePaging(410, 850, mainFont, #38620C);

  // === prepare words === //
  shuffleWords();
  println(ver);
  println("\nAs AJ Hoge says, reciting English words is not a good method.\nWe should always learn English words in articles, in sentences, in phrases, in real environment, instead of individually.");
  println("So, I suppose you've learned those words in real environment. I'd rather say this application is for you to review, not recite.");
  println("Enjoy your studying maths, physics, and chemistry in English language!");
  println("\nThis application is running in MIT Processing 4.3\nhttps://processing.org/");
  println("\ntotal words: " + totalWords + "\ntime out minutes: " + tmo);
  println("\n\nmouse right click or two fingers tapping on touchpad to print current word info to console.\n");
}

// ============ draw backgound ============ //
void drawBg() {
  background(bgColor);
  image(logoImg, 1100, 790);
  image(sealImg, 1090, 0);

  textSize(25);
  text(ver, 1240, 40);
  text("'s' for slide show, other key to recit", 20, 880);
}

// ============ draw type, word and image of the word ============ //
void showInfo(String prefix, int n, int cnt, String file) {
  String str;
  str = type + "   " + prefix + nf(n + 1) + " of " + nf(cnt) + "         " + file;
  textSize(22);
  text(str, 10, 28);
}

void showWord() {
  if (word.length() > 28) {
    textSize(52);
    text(word, 50, 80);
  } else {
    textSize(90);
    text(word, 50, 120);
  }
}

void showImg() {
  image(wordImg, 50, 150, wordImg.width * zoom, wordImg.height * zoom);
}

// ============ main draw loop ============ //
void draw() {
  drawBg();

  // ================ start of state machines ================ //
  switch(stateMachine) {
    // === recite === //
  case 0:
    {
      // read out word data
      type = words[pos][0];
      word = words[pos][1];
      file = words[pos][2];
      wordImg = loadImage(file);

      // best fit the show area
      if (wordImg.width > maxW || wordImg.height > maxH) {
        // img too big, zoom to biggest factor
        float w_zoom = (float)(1500) / wordImg.width;
        float h_zoom = (float)(630) / wordImg.height;
        zoom = min(w_zoom, h_zoom);
      } else {
        // img width and height fit show area enough, not need to zoom
        zoom = 1.0;
      }

      stateMachine = 1;
      break;
    }

  case 1:
    {
      showInfo("", pos, totalWords, file);
      showWord();
      break;
    }

  case 2:
    {
      showInfo("", pos, totalWords, file);
      showWord();
      showImg();
      break;
    }

  case 3:
    {
      if (++pos >= totalWords) {
        pos = 0;
      }
      stateMachine = 0;
      break;
    }

    // === slide show === //
  case 10:
    {
      pos = 0;
      stateMachine = 11;
      break;
    }

  case 11:
    {
      // read out word data
      type = words[pos][0];
      word = words[pos][1];
      file = words[pos][2];
      wordImg = loadImage(file);
      stateMachine = 12;
      break;
    }

  case 12:
    {
      // best fit the show area
      if (wordImg.width > maxW || wordImg.height > maxH) {
        // img too big, zoom to biggest factor
        float w_zoom = (float)(1500) / wordImg.width;
        float h_zoom = (float)(630) / wordImg.height;
        zoom = min(w_zoom, h_zoom);
      } else {
        zoom = 1.0; // img width and height fit show area enough, not need to zoom
      }

      showInfo("slide show ", pos, totalWords, file);
      showWord();
      showImg();

      break;
    }

  case 13:
    {
      if (++pos >= totalWords) {
        stateMachine = 14; // 1 round done, restar slide show
      } else {
        stateMachine = 11; // next slide
      }
      break;
    }

  case 14:
    {
      textSize(90);
      text("slide show finished", 300, 480);
      break;
    }

  case 15:
    {
      stateMachine = 10; // restar slide show
      break;
    }

    // === splash screen === //
  case -10: // 'h' screen (and splash screen also)
    {
      splashImg = loadImage("splash1.png");
      stateMachine++;
      // no break;
    }

  case -9:
    {
      image(splashImg, 30, 20);
      text("total " + totalWords + " words", 900, 30);
      break;
    }

  case -8:
    {
      splashImg = loadImage("splash2.png");
      stateMachine++;
      // no break;
    }

  case -7:
    {
      image(splashImg, 60, 180);
      break;
    }

  case -6:
    {
      splashImg = loadImage("splash3.png");
      stateMachine++;
      // no break;
    }

  case -5:
    {
      image(splashImg, 40, 180);
      break;
    }

  case -4:
    {
      splashImg = loadImage("splash4.png");
      stateMachine++;
      // no break;
    }

  case -3:
    {
      image(splashImg, 40, 25);
      break;
    }

  case -2:
    {
      splashImg = loadImage("PeriodicTable2.png");
      stateMachine++;
      // no break;
    }

  case -1:
    {
      background(bgColor);
      image(splashImg, 45, 5);
      break;
    }

    // === default or other illegal state machine === //
  default:
    {
      stateMachine = 0; // recite mode
    }
  }

  // ================ end of state machines ================ //

  // === mouse move paging msg, animation pen and cursor, stopwatch, cursor === //
  mouseMovePaging.show();
  animatePen.show();
  stopWatch.show();
}

// ============ key press - handle mode change ============ //
void keyPressed() {
  if (key == 's') {
    stateMachine = 10; // 's' for slide show
  } else if (key == 'h') {
    stateMachine = - 10; // 'h' screen (and splash screen also)
  } else if (key == ' ') { // SPACE to disable/enable mouse move paging
    mouseMovePaging.toggle();
  } else {
    stateMachine = 0; // other keys = recite mode
  }
}

// ============ shuffle words array ============ //
void shuffleWords() {
  String  line [];

  for (int i = 1000; i > 0; i--) { // swap 1000 rounds
    // random select 2 pos to swap
    int a = (int)random(totalWords);
    int b = (int)random(totalWords);

    // swap
    line = words[a];
    words[a] = words[b];
    words[b] = line;
  }
}
